home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / ICMPCMD.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  6KB  |  264 lines

  1. /* ICMP-related user commands */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "icmp.h"
  5. #include "mbuf.h"
  6. #include "netuser.h"
  7. #include "internet.h"
  8. #include "timer.h"
  9. #include "socket.h"
  10. #include "proc.h"
  11. #include "session.h"
  12. #include "cmdparse.h"
  13. #include "commands.h"
  14.  
  15. static int doicmpec __ARGS((int argc, char *argv[],void *p));
  16. static int doicmpstat __ARGS((int argc, char *argv[],void *p));
  17. static int doicmptr __ARGS((int argc, char *argv[],void *p));
  18. static void pingtx __ARGS((int s,void *ping1,void *p));
  19. static int pingem __ARGS((int s,int16 seq,int16 id,int16 len));
  20.  
  21. static struct cmds Icmpcmds[] = {
  22.     "echo",        doicmpec,    0, 0, NULLCHAR,
  23.     "status",    doicmpstat,    0, 0, NULLCHAR,
  24.     "trace",    doicmptr,    0, 0, NULLCHAR,
  25.     NULLCHAR
  26. };
  27.  
  28. int Icmp_trace;
  29. static int Icmp_echo = 1;
  30.  
  31. int
  32. doicmp(argc,argv,p)
  33. int argc;
  34. char *argv[];
  35. void *p;
  36. {
  37.     return subcmd(Icmpcmds,argc,argv,p);
  38. }
  39.  
  40. static int
  41. doicmpstat(argc,argv,p)
  42. int argc;
  43. char *argv[];
  44. void *p;
  45. {
  46.     register int i;
  47.  
  48.     printf("ICMP: chksum err %u no space %u icmp %u bdcsts %u\n",
  49.      Icmp_errors.checksum,Icmp_errors.nospace,Icmp_errors.noloop,
  50.      Icmp_errors.bdcsts);
  51.     printf("type  rcvd  sent\n");
  52.     for(i=0;i<ICMP_TYPES;i++){
  53.         if(Icmp_stats.input[i] == 0 && Icmp_stats.output[i] == 0)
  54.             continue;
  55.         printf("%-6u%-6u%-6u",i,Icmp_stats.input[i],
  56.             Icmp_stats.output[i]);
  57.         printf("  %s",Icmptypes[i]);
  58.         printf("\n");
  59.     }
  60.     return 0;
  61. }
  62. static int
  63. doicmptr(argc,argv,p)
  64. int argc;
  65. char *argv[];
  66. void *p;
  67. {
  68.     return setbool(&Icmp_trace,"ICMP tracing",argc,argv);
  69. }
  70. static int
  71. doicmpec(argc,argv,p)
  72. int argc;
  73. char *argv[];
  74. void *p;
  75. {
  76.     return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
  77. }
  78.  
  79. /* Send ICMP Echo Request packets */
  80. int
  81. doping(argc,argv,p)
  82. int argc;
  83. char *argv[];
  84. void *p;
  85. {
  86.     struct proc *pinger = NULLPROC;    /* Transmit process */
  87.     struct sockaddr_in to,from;
  88.     struct icmp icmp;
  89.     struct mbuf *bp;
  90.     int32 timestamp,rtt,abserr;
  91.     int s,fromlen;
  92.     struct ping ping;
  93.     struct session *sp;
  94.  
  95.     memset((char *)&ping,0,sizeof(ping));
  96.     /* Allocate a session descriptor */
  97.     if((sp = newsession(argv[1],PING)) == NULLSESSION){
  98.         printf("Too many sessions\n");
  99.         freeargs(argc,argv);
  100.         return 1;
  101.     }
  102.     sp->cb.ping = &ping;
  103.     ping.sp = sp;
  104.  
  105.     ping.proc = Curproc;
  106.     if((sp->s = s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == -1){
  107.         printf("Can't create socket\n");
  108.         freesession(sp);
  109.         freeargs(argc,argv);
  110.         return 1;
  111.     }
  112.     Current = sp;
  113.     Mode = CONV_MODE;
  114.     to.sin_family = AF_INET;
  115.     if((to.sin_addr.s_addr = resolve(argv[1])) == 0){
  116.         printf("Host %s unknown\n",argv[1]);
  117.         close_s(s);
  118.         freesession(sp);
  119.         freeargs(argc,argv);
  120.         return 1;
  121.     }
  122.     connect(s,(char *)&to,sizeof(to));
  123.  
  124.     if(argc > 2)
  125.         ping.len = atoi(argv[2]);
  126.  
  127.     if(argc > 3)
  128.         ping.interval = atoi(argv[3]);
  129.  
  130.     freeargs(argc,argv);
  131.     if(ping.interval != 0){
  132.         pinger = newproc("pingtx",300,pingtx,s,&ping,NULL);
  133.     } else {
  134.         /* One shot ping; let echo_proc hook handle response.
  135.          * An ID of MAXINT16 will not be confused with a legal socket
  136.          * number, which is used to identify repeated pings
  137.          */
  138.         pingem(s,0,MAXINT16,ping.len);
  139.         close_s(s);
  140.         freesession(sp);
  141.         return 0;
  142.     }
  143.     /* Now collect the replies */
  144.     for(;;){
  145.         fromlen = sizeof(from);
  146.         if(recv_mbuf(s,&bp,0,0,(char *)&from,&fromlen) == -1)
  147.             break;
  148.         ntohicmp(&icmp,&bp);
  149.         if(icmp.type != ECHO_REPLY
  150.          || from.sin_addr.s_addr != to.sin_addr.s_addr
  151.          || icmp.args.echo.id != s){
  152.             /* Ignore other people's responses */
  153.             free_p(bp);
  154.             continue;
  155.         }
  156.         ping.responses++;
  157.         /* Get stamp */
  158.         if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  159.          != sizeof(timestamp)){
  160.             /* The timestamp is missing! */
  161.             free_p(bp);    /* Probably not necessary */
  162.             continue;
  163.         }
  164.         free_p(bp);
  165.  
  166.         /* Compute round trip time, update smoothed estimates */
  167.         rtt = (Clock - timestamp) * MSPTICK;
  168.         abserr = rtt > ping.srtt ? rtt - ping.srtt : ping.srtt - rtt;
  169.         if(ping.responses == 1){
  170.             /* First response, base entire SRTT on it */
  171.             ping.srtt = rtt;
  172.         } else {
  173.             ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
  174.         }
  175.         ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
  176.  
  177.     }
  178.     if(Current == sp && Mode == CONV_MODE)
  179.         printf("\n");
  180.     if(pinger != NULLPROC)
  181.         killproc(pinger);
  182.     close_s(s);
  183.     freesession(sp);
  184.     return 0;
  185. }
  186. void
  187. echo_proc(source,dest,icmp,bp)
  188. int32 source;
  189. int32 dest;
  190. struct icmp *icmp;
  191. struct mbuf *bp;
  192. {
  193.     int32 timestamp,rtt;
  194.  
  195.     if(Icmp_echo && icmp->args.echo.id == MAXINT16
  196.      && pullup(&bp,(char *)×tamp,sizeof(timestamp))
  197.      == sizeof(timestamp)){
  198.         /* Compute round trip time */
  199.         rtt = (Clock - timestamp) * MSPTICK;
  200.         printf("%s: rtt %lu\n",inet_ntoa(source),rtt);
  201.     }
  202.     free_p(bp);
  203. }
  204. /* Ping transmit process. Runs until killed */
  205. static void
  206. pingtx(s,ping1,p)
  207. int s;        /* Socket to use */
  208. void *ping1;
  209. void *p;
  210. {
  211.     struct ping *ping;
  212.     long sdur;
  213.  
  214.     ping = (struct ping *)ping1;
  215.     sdur = ping->interval * (1000 / MSPTICK);
  216.     ping->sent = 0;
  217.     for(;;){
  218.         if(Current == ping->sp && Mode == CONV_MODE){
  219.             printf("pinging %s: sent %lu rcvd %lu avg rtt %lu mdev %lu    \r",
  220.              ping->sp->name,ping->sent,ping->responses,ping->srtt,
  221.              ping->mdev);
  222.         }
  223.         pingem(s,(int16)ping->sent++,s,ping->len);
  224.         pause(sdur);
  225.     }
  226. }
  227.  
  228.  
  229. /* Send ICMP Echo Request packet */
  230. static int
  231. pingem(s,seq,id,len)
  232. int s;        /* Raw socket on which to send ping */
  233. int16 seq;    /* ICMP Echo Request sequence number */
  234. int16 id;    /* ICMP Echo Request ID */
  235. int16 len;    /* Length of optional data field */
  236. {
  237.     struct mbuf *data = NULLBUF;
  238.     struct mbuf *bp;
  239.     struct icmp icmp;
  240.  
  241.     if((data = alloc_mbuf(len+sizeof(Clock))) == NULLBUF)
  242.         return -1;
  243.     data->cnt = len+sizeof(Clock);
  244.     /* Set optional data field, if any, to all 55's */
  245.     if(len != 0)
  246.         memset(data->data+sizeof(Clock),0x55,len);
  247.  
  248.     /* Insert timestamp and build ICMP header */
  249.     memcpy(data->data,(char *)&Clock,sizeof(Clock));
  250.     Icmp_stats.output[ECHO]++;
  251.     icmp.type = ECHO;
  252.     icmp.code = 0;
  253.     icmp.args.echo.seq = seq;
  254.     icmp.args.echo.id = id;
  255.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  256.         free_p(data);
  257.         return 0;
  258.     }
  259.     send_mbuf(s,bp,0,NULLCHAR,0);
  260.     return 0;
  261. }
  262.  
  263.  
  264.